/**
 * Loads a JavaScript file and returns a Promise for when it is loaded
 */
const loadScript = async (src, id = undefined) => {
    return new Promise((resolve, reject) => {
        src = String(src)
        id = id || src.substring(src.lastIndexOf('/') + 1)
        const oldScript = document.getElementById(id);
        const newScript = document.createElement('script')
        newScript.id = id
        newScript.type = 'text/javascript'
        newScript.onload = resolve
        newScript.onerror = reject
        newScript.src = src
        if ((oldScript === undefined) || (oldScript === null)) {
            document.body.appendChild(newScript)
        } else {
            document.body.replaceChild(newScript, oldScript)
        }
    })
}

let icon = (name, width = 16, height = 16, color = 'currentColor') => {
    return `
		<svg class="bi" width="${width}" height="${height}" fill="${color}">
	  		<use xlink:href="/icons/icons.svg#${name}"/>
		</svg>
	`;
}

// Fetch Post content via AJAX
document.querySelectorAll('.item').forEach((el) => {
    el.addEventListener('click', (event) => {
        document.querySelector('.item-selected').classList.remove('item-selected');
        event.currentTarget/*.querySelector('.item')*/.classList.add('item-selected');
        document.cookie = `currentId=${event.currentTarget.id}`
        fetch(`/posts/${event.currentTarget.id}/view`)
            .then(response => response.text())
            .then(
                data => {
                    document.getElementById('main').innerHTML = data;
                    loadScript('/javascripts/view.js', 'view.js');
                }
            );
    });
});

// POST method implementation:
async function postData(url = '', formData) {
    let headers = new Headers();
    // headers.append('Content-Type', 'application/x-www-form-urlencoded');
    headers.append('X-Requested-With', 'XMLHttpRequest');
    // Default options are marked with *
    const response = await fetch(url, {
        method: 'POST', // *GET, POST, PUT, DELETE, etc.
        mode: 'same-origin', // no-cors, *cors, same-origin
        cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
        credentials: 'same-origin', // include, *same-origin, omit
        headers: headers,
        redirect: 'follow', // manual, *follow, error
        referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
        body: formData // body data type must match "Content-Type" header
    });
    return response.json(); // parses JSON response into native JavaScript objects
};

const createObjectStore = async (transaction, objectStoreName) => {
    return new Promise((resolve, reject) => {
        try {
            const objectStore = transaction.objectStore(objectStoreName)
            resolve(objectStore)
        } catch (error) {
            reject(error)
        }
    })
}

const createTransaction = async (db, objectStoreName, mode = 'read') => {
    return new Promise((resolve, reject) => {
        try {
            const transaction = db.transaction(objectStoreName, mode)
            console.log(`${transaction.mode} transaction has been created sucessfuly on database: ${transaction.db.name} and object store(s): ` + Array.from(transaction.objectStoreNames).join(', '))
            resolve(transaction)
        } catch (error) {
            reject(error)
        }
    })
}

const createDataBase = async (dbName, dbVersion = 1, onupgradeneeded = () => { }) => {
    return new Promise((resolve, reject) => {
        if (!dbName) {
            throw new Error('Param: dbName is mandatory!')
        }
        if (!window.indexedDB) {
            throw new Error('Your browser doesn\'t support a stable version of IndexedDB.')
        }
        const dbRequest = window.indexedDB.open(dbName, dbVersion)
        dbRequest.onsuccess = resolve
        dbRequest.onerror = reject
        dbRequest.onupgradeneeded = onupgradeneeded
    })
}


let dbExec = (documentDB, document, method = 'get') => {
    return new Promise((resolve, reject) => {
        documentDB.then(event => {
            const db = event.target.result
            createTransaction(db, 'document', 'readwrite').then(transaction => {
                createObjectStore(transaction, 'document').then(objectStore => {
                    let req
                    switch (method) {
                        case 'put':
                            req = objectStore.put(document)
                            break;

                        default:
                            req = objectStore.get(document._id)
                            break;
                    }
                    req.onsuccess = resolve
                    req.onerror = reject
                })
                transaction.oncomplete = event => {
                    console.log('Transaction completed!')
                }
                transaction.onerror = event => {
                    console.log('Transaction error!')
                }
                transaction.onabort = event => {
                    console.log('Transaction aborted!')
                }
            })
        }).catch(error => { throw error })
    })
}

const doFetch = endPoint => {
    fetch(endPoint)
        .then(response => response.text())
        .then(
            async data => {
                document.getElementById('main').innerHTML = data;
                loadScript('https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.5/codemirror.min.js')
                    .then(
                        () => {
                            loadScript('https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.5/mode/markdown/markdown.min.js')
                                .then(
                                    () => {
                                        let editor = CodeMirror.fromTextArea(
                                            document.getElementById('editor'),
                                            {
                                                lineNumbers: true,
                                                mode: 'markdown',
                                                lineWrapping: true
                                            }
                                        );
                                        editor.setSize('100%', '100%');
                                        editor.on('change', instance => { instance.save() })
                                    }
                                )
                                .then(
                                    async () => {
                                        fetch('/config/AUTOSAVE_FREQ')
                                            .then(response => response.text())
                                            .then(autosaveFreq => {
                                                if (autosaveFreq > 0) {

                                                    const documentDB = createDataBase(
                                                        'markdowns',
                                                        1,
                                                        // On upgrade needed
                                                        event => {
                                                            const db = event.target.result
                                                            if (!db.objectStoreNames.contains('document')) {
                                                                db.createObjectStore('document', { keyPath: '_id' })
                                                            }
                                                        }
                                                    )
                                                    let formData = new FormData(document.querySelector('form'))
                                                    let currentContent = JSON.stringify(Array.from(formData.entries()))
                                                    dbExec(documentDB, {
                                                        _id: 1,
                                                        content: currentContent
                                                    },
                                                        'put'
                                                    ).then(event => console.log(event.target.result))

                                                    intervalId = setInterval(
                                                        () => {
                                                            dbExec(
                                                                documentDB,
                                                                {
                                                                    _id: 1
                                                                },
                                                                'get'
                                                            ).then(event => {
                                                                let formData = new FormData(document.querySelector('form'))
                                                                let data = {}
                                                                // Convert Iterator to Javascript Object
                                                                for (const key of formData.keys()) {
                                                                    data[key] = formData.get(key)
                                                                }
                                                                // Convert Object to JSON
                                                                let currentContent = JSON.stringify(data)
                                                                savedContent = event.target.result.content
                                                                if (savedContent != currentContent) {
                                                                    const headers = new Headers({
                                                                        "Content-Type": "application/json"
                                                                    })
                                                                    const request = new Request(
                                                                        '/posts', {
                                                                        headers: headers,
                                                                        method: formData.get('id') && 'PUT' || 'POST',
                                                                        body: currentContent
                                                                    }
                                                                    )
                                                                    fetch(request).then(response => console.log(response))
                                                                } else {
                                                                    console.log('Content are identical no autosaving!!!')
                                                                }
                                                            })
                                                        },
                                                        autosaveFreq * 1000
                                                    )
                                                }
                                            })

                                    }
                                )
                        }
                    );
            }
        ).then(() => {
            document.getElementById('post').addEventListener('submit', (e) => {
                e.preventDefault()
            })
        })
}

// Edit Post form
document.querySelector('#new').addEventListener('click', event => {
    const endPoint = event.currentTarget.id == 'new' ? '/posts/new' : `/posts/${event.currentTarget.dataset.id}/${event.currentTarget.id}`
    doFetch(endPoint)
})